package com.ecommerce.user.service.impl;

import com.ecommerce.common.core.ApiResult;
import com.ecommerce.common.core.PageResult;
import com.ecommerce.common.exception.BusinessException;
import com.ecommerce.common.exception.ResourceNotFoundException;
import com.ecommerce.user.dto.ChangePasswordRequest;
import com.ecommerce.user.dto.UserInfoResponse;
import com.ecommerce.user.dto.UserLoginRequest;
import com.ecommerce.user.dto.UserQueryRequest;
import com.ecommerce.user.dto.UserRegisterRequest;
import com.ecommerce.user.dto.UserUpdateRequest;
import com.ecommerce.user.entity.User;
import com.ecommerce.user.entity.UserProfile;
import com.ecommerce.user.repository.UserProfileRepository;
import com.ecommerce.user.repository.UserRepository;
import com.ecommerce.user.service.UserService;
import com.ecommerce.user.util.JwtTokenUtil;
import com.ecommerce.user.util.PasswordEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * 用户服务实现类
 */
@Service
@Transactional
public class UserServiceImpl implements UserService {
    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserProfileRepository userProfileRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String USER_CACHE_PREFIX = "user:info:";
    private static final Duration USER_CACHE_EXPIRE = Duration.ofHours(2);

    @Override
    public ApiResult<UserInfoResponse> register(UserRegisterRequest request) {
        log.info("用户注册请求: {}", request.getUsername());

        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            return ApiResult.badRequest("用户名已存在");
        }

        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            return ApiResult.badRequest("邮箱已被注册");
        }

        // 检查手机号是否已存在
        if (request.getPhone() != null && userRepository.existsByPhone(request.getPhone())) {
            return ApiResult.badRequest("手机号已被注册");
        }

        try {
            // 创建用户
            User user = User.builder()
                    .username(request.getUsername())
                    .password(passwordEncoder.encode(request.getPassword()))
                    .email(request.getEmail())
                    .phone(request.getPhone())
                    .nickname(request.getNickname())
                    .status(1)
                    .build();

            user = userRepository.save(user);

            // 创建用户详情
            UserProfile profile = UserProfile.builder()
                    .userId(user.getId())
                    .build();
            userProfileRepository.save(profile);

            log.info("用户注册成功: userId={}", user.getId());

            return ApiResult.success("注册成功", UserInfoResponse.fromUser(user));

        } catch (Exception e) {
            log.error("用户注册失败: {}", e.getMessage(), e);
            throw new BusinessException("注册失败，请稍后重试");
        }
    }

    @Override
    public ApiResult<String> login(UserLoginRequest request) {
        log.info("用户登录请求: {}", request.getUsername());

        try {
            // 查找用户
            User user = userRepository.findByUsername(request.getUsername())
                    .orElseThrow(() -> new BusinessException(401, "用户名或密码错误"));

            // 检查用户状态
            if (user.getStatus() == 0) {
                return ApiResult.forbidden("账户已被禁用");
            }

            // 验证密码
            if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
                return ApiResult.error(401, "用户名或密码错误");
            }

            // 更新最后登录信息
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(getClientIp());
            userRepository.save(user);

            // 生成JWT令牌
            String token = jwtTokenUtil.generateToken(user.getId(), user.getUsername());

            // 缓存用户信息
            cacheUserInfo(user);

            log.info("用户登录成功: userId={}", user.getId());

            return ApiResult.success("登录成功", token);

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("用户登录失败: {}", e.getMessage(), e);
            throw new BusinessException("登录失败，请稍后重试");
        }
    }

    @Override
    @Transactional(readOnly = true)
    public ApiResult<UserInfoResponse> getUserInfo(Long userId) {
        // 先从缓存获取
        UserInfoResponse cachedUser = getCachedUserInfo(userId);
        if (cachedUser != null) {
            return ApiResult.success(cachedUser);
        }

        // 从数据库获取
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户不存在"));

        UserInfoResponse userInfo = UserInfoResponse.fromUser(user);

        // 缓存用户信息
        cacheUserInfo(user);

        return ApiResult.success(userInfo);
    }

    public ApiResult<UserInfoResponse> updateUserInfo(Long userId, UserUpdateRequest request) {
        log.info("更新用户信息请求: userId={}", userId);

        try {
            // 查找用户
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new ResourceNotFoundException("用户不存在"));

            // 检查用户状态
            if (user.getStatus() == 0) {
                return ApiResult.forbidden("账户已被禁用，无法更新信息");
            }

            // 检查邮箱是否被其他用户使用
            if (request.getEmail() != null && !request.getEmail().equals(user.getEmail())) {
                if (userRepository.existsByEmail(request.getEmail())) {
                    return ApiResult.badRequest("邮箱已被其他用户使用");
                }
                user.setEmail(request.getEmail());
            }

            // 检查手机号是否被其他用户使用
            if (request.getPhone() != null && !request.getPhone().equals(user.getPhone())) {
                if (userRepository.existsByPhone(request.getPhone())) {
                    return ApiResult.badRequest("手机号已被其他用户使用");
                }
                user.setPhone(request.getPhone());
            }

            // 更新用户信息
            if (request.getNickname() != null) {
                user.setNickname(request.getNickname());
            }
            if (request.getAvatar() != null) {
                user.setAvatar(request.getAvatar());
            }
            if (request.getGender() != null) {
                user.setGender(request.getGender());
            }
            if (request.getBirthday() != null) {
                user.setBirthday(request.getBirthday());
            }

            user.setUpdateTime(LocalDateTime.now());
            user = userRepository.save(user);

            // 清除缓存
            clearUserCache(userId);

            // 重新缓存用户信息
            cacheUserInfo(user);

            log.info("用户信息更新成功: userId={}", userId);

            return ApiResult.success("用户信息更新成功", UserInfoResponse.fromUser(user));

        } catch (ResourceNotFoundException e) {
            throw e;
        } catch (Exception e) {
            log.error("更新用户信息失败: userId={}, error={}", userId, e.getMessage(), e);
            throw new BusinessException("更新用户信息失败，请稍后重试");
        }
    }

    public ApiResult<Void> changePassword(Long userId, ChangePasswordRequest request) {
        log.info("修改密码请求: userId={}", userId);

        try {
            // 验证新密码和确认密码是否一致
            if (!request.isPasswordMatching()) {
                return ApiResult.badRequest("两次输入的新密码不一致");
            }

            // 查找用户
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new ResourceNotFoundException("用户不存在"));

            // 检查用户状态
            if (user.getStatus() == 0) {
                return ApiResult.forbidden("账户已被禁用，无法修改密码");
            }

            // 验证旧密码
            if (!passwordEncoder.matches(request.getOldPassword(), user.getPassword())) {
                return ApiResult.badRequest("旧密码错误");
            }

            // 更新密码
            user.setPassword(passwordEncoder.encode(request.getNewPassword()));
            user.setUpdateTime(LocalDateTime.now());
            userRepository.save(user);

            // 清除缓存
            clearUserCache(userId);

            log.info("密码修改成功: userId={}", userId);

            return ApiResult.success("密码修改成功");

        } catch (ResourceNotFoundException e) {
            throw e;
        } catch (Exception e) {
            log.error("修改密码失败: userId={}, error={}", userId, e.getMessage(), e);
            throw new BusinessException("修改密码失败，请稍后重试");
        }
    }

    @Transactional(readOnly = true)
    public ApiResult<PageResult<UserInfoResponse>> pageUsers(UserQueryRequest request) {
        log.info("分页查询用户请求: {}", request);

        try {
            // 创建分页请求
            Sort.Direction direction = "desc".equalsIgnoreCase(request.getOrderDirection()) 
                    ? Sort.Direction.DESC : Sort.Direction.ASC;
            Sort sort = Sort.by(direction, request.getOrderBy());
            Pageable pageable = PageRequest.of(request.getPageNum() - 1, request.getPageSize(), sort);

            // 构建查询条件
            Specification<User> spec = (root, query, criteriaBuilder) -> {
                var predicates = criteriaBuilder.conjunction();

                if (request.getUsername() != null && !request.getUsername().trim().isEmpty()) {
                    predicates = criteriaBuilder.and(predicates,
                            criteriaBuilder.like(root.get("username"), "%" + request.getUsername().trim() + "%"));
                }

                if (request.getEmail() != null && !request.getEmail().trim().isEmpty()) {
                    predicates = criteriaBuilder.and(predicates,
                            criteriaBuilder.like(root.get("email"), "%" + request.getEmail().trim() + "%"));
                }

                if (request.getPhone() != null && !request.getPhone().trim().isEmpty()) {
                    predicates = criteriaBuilder.and(predicates,
                            criteriaBuilder.like(root.get("phone"), "%" + request.getPhone().trim() + "%"));
                }

                if (request.getNickname() != null && !request.getNickname().trim().isEmpty()) {
                    predicates = criteriaBuilder.and(predicates,
                            criteriaBuilder.like(root.get("nickname"), "%" + request.getNickname().trim() + "%"));
                }

                if (request.getStatus() != null) {
                    predicates = criteriaBuilder.and(predicates,
                            criteriaBuilder.equal(root.get("status"), request.getStatus()));
                }

                if (request.getCreateTimeBegin() != null && !request.getCreateTimeBegin().trim().isEmpty()) {
                    try {
                        LocalDateTime beginTime = java.time.LocalDateTime.parse(request.getCreateTimeBegin().replace(" ", "T"));
                        predicates = criteriaBuilder.and(predicates,
                                criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), beginTime));
                    } catch (Exception e) {
                        log.warn("开始时间格式不正确: {}", request.getCreateTimeBegin());
                    }
                }

                if (request.getCreateTimeEnd() != null && !request.getCreateTimeEnd().trim().isEmpty()) {
                    try {
                        LocalDateTime endTime = java.time.LocalDateTime.parse(request.getCreateTimeEnd().replace(" ", "T"));
                        predicates = criteriaBuilder.and(predicates,
                                criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), endTime));
                    } catch (Exception e) {
                        log.warn("结束时间格式不正确: {}", request.getCreateTimeEnd());
                    }
                }

                return predicates;
            };

            // 执行查询
            Page<User> userPage = userRepository.findAll(spec, pageable);

            // 转换为响应DTO
            PageResult<UserInfoResponse> pageResult = PageResult.<UserInfoResponse>builder()
                    .list(userPage.getContent().stream()
                            .map(UserInfoResponse::fromUser)
                            .collect(java.util.stream.Collectors.toList()))
                    .total(userPage.getTotalElements())
                    .totalPage(userPage.getTotalPages())
                    .pageNum(request.getPageNum())
                    .pageSize(request.getPageSize())
                    .build();

            log.info("分页查询用户成功: 总记录数={}, 总页数={}", 
                    userPage.getTotalElements(), userPage.getTotalPages());

            return ApiResult.success(pageResult);

        } catch (Exception e) {
            log.error("分页查询用户失败: error={}", e.getMessage(), e);
            throw new BusinessException("查询用户失败，请稍后重试");
        }
    }

    @Override
    public ApiResult<Void> updateUserStatus(Long userId, Integer status) {
        log.info("更新用户状态请求: userId={}, status={}", userId, status);

        try {
            // 参数验证
            if (status == null || (status != 0 && status != 1)) {
                return ApiResult.badRequest("状态值只能是0(禁用)或1(启用)");
            }

            // 查找用户
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new ResourceNotFoundException("用户不存在"));

            // 检查状态是否已相同
            if (user.getStatus().equals(status)) {
                String message = status == 1 ? "用户已经是启用状态" : "用户已经是禁用状态";
                return ApiResult.badRequest(message);
            }

            // 更新状态
            user.setStatus(status);
            user.setUpdateTime(LocalDateTime.now());
            userRepository.save(user);

            // 清除缓存
            clearUserCache(userId);

            log.info("用户状态更新成功: userId={}, status={}", userId, status);

            return ApiResult.success("用户状态更新成功");

        } catch (ResourceNotFoundException e) {
            throw e;
        } catch (Exception e) {
            log.error("更新用户状态失败: userId={}, status={}, error={}", 
                    userId, status, e.getMessage(), e);
            throw new BusinessException("更新用户状态失败，请稍后重试");
        }
    }

    private void clearUserCache(Long userId) {
        redisTemplate.delete(USER_CACHE_PREFIX + userId);
    }

    /**
     * 缓存用户信息
     */
    private void cacheUserInfo(User user) {
        try {
            String cacheKey = USER_CACHE_PREFIX + user.getId();
            UserInfoResponse userInfo = UserInfoResponse.fromUser(user);
            redisTemplate.opsForValue().set(cacheKey, userInfo, USER_CACHE_EXPIRE);
        } catch (Exception e) {
            log.warn("缓存用户信息失败: userId={}, error={}", user.getId(), e.getMessage());
        }
    }

    /**
     * 获取缓存的用户信息
     */
    private UserInfoResponse getCachedUserInfo(Long userId) {
        try {
            String cacheKey = USER_CACHE_PREFIX + userId;
            return (UserInfoResponse) redisTemplate.opsForValue().get(cacheKey);
        } catch (Exception e) {
            log.warn("获取缓存用户信息失败: userId={}, error={}", userId, e.getMessage());
            return null;
        }
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp() {
        // 简化实现，实际应该从HttpServletRequest获取
        return "127.0.0.1";
    }
}